package models

import (
	"crypto/sha1"
	"encoding/json"
	"fmt"
	"gitchina/CPTT4WeChat/util"
	"io/ioutil"
	"net/http"
	"time"
)

var AppToken = "MV345LLwrioZZ0X"
var AppKey = "cbb8fb701f1944bf1ba60b6f42573300"
var AppId = "wxcd8068ed736b2f72"

type WeChat struct{}

type AccessToken struct {
	Token     string `json:"access_token"`
	ExpiresIn int    `json:"expires_in"`
}

type WeChatUserInfo struct {
	Subscribe     int    `json:"subscribe"`
	OpenId        string `json:"openid"`
	NickName      string `json:"nickname"`
	Sex           int    `json:"sex"`
	Language      string `json:"language"`
	City          string `json:"city"`
	Province      string `json:"province"`
	Country       string `json:"country"`
	HeadImgUrl    string `json:"headimgurl"`
	SubscribeTime int64  `json:"subscribe_time"`
	UnionId       string `json:"unionid"`
	Remark        string `json:"remark"`
	GroupId       int    `json:"groupid"`
}

func init() {
	util.NewCache(util.User_Channel, util.InMemory, time.Hour)
	util.NewCache(util.User_Cache, util.InMemory, 2*time.Hour)
	util.NewCache(util.Garden_Cache, util.InMemory, 30*24*time.Hour)
	util.NewCacheL(util.Access_Token_Cache, util.InMemory, util.ValueReloader{
		Fn:       func() (interface{}, bool) { return getAccessToken() },
		Interval: 7200 * time.Second,
		Key:      util.Access_Token_Cache,
	})
	util.NewCache(util.Grade_Stats_Cache, util.InMemory, 3*time.Minute)
	util.NewCache(util.Class_Stats_Cache, util.InMemory, 3*time.Minute)
	util.NewCache(util.Options_Cache, util.InMemory, 30*24*time.Hour)
	util.NewCache(util.Check_InOut_Data_Cache, util.InMemory, 30*24*time.Hour)
}

func (w WeChat) Init() {
	w.GetAccessToken()
}

func (w WeChat) CheckSignature(signature, ts, nonce string) bool {
	return signature == fmt.Sprintf("%x", sha1.Sum([]byte(fmt.Sprintf("%s%s%s", ts, nonce, AppToken))))

	// s1 := fmt.Sprintf("%x", sha1.Sum([]byte(fmt.Sprintf("%s%s%s", nonce, ts, Token))))
	// s2 := fmt.Sprintf("%x", sha1.Sum([]byte(fmt.Sprintf("%s%s%s", nonce, Token, ts))))
	// s3 := fmt.Sprintf("%x", sha1.Sum([]byte(fmt.Sprintf("%s%s%s", ts, nonce, Token))))
	// s4 := fmt.Sprintf("%x", sha1.Sum([]byte(fmt.Sprintf("%s%s%s", ts, Token, nonce))))
	// s5 := fmt.Sprintf("%x", sha1.Sum([]byte(fmt.Sprintf("%s%s%s", Token, ts, nonce))))
	// s6 := fmt.Sprintf("%x", sha1.Sum([]byte(fmt.Sprintf("%s%s%s", Token, nonce, Token))))
}

func (w WeChat) GetAccessToken() (token string, ok bool) {
	var val interface{}
	var cache util.Cache
	if cache, ok = util.GetCache(util.Access_Token_Cache); ok {
		if val, ok = cache.Get(util.Access_Token_Cache); ok {
			token = val.(*AccessToken).Token
		} else {
			if val, ok = getAccessToken(); ok {
				token = val.(*AccessToken).Token
			}
		}
	}
	return
}

func (w WeChat) GetWeChatUserInfo(openId string) (info *WeChatUserInfo, ok bool) {
	var token string
	info = &WeChatUserInfo{}
	if token, ok = w.GetAccessToken(); ok {
		url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN", token, openId)
		if err := httpGet(url, info); err != nil {
			util.GetLogger().Error("[handle-GetWeChatUserInfo] - error:%s", err.Error())
		} else {
			ok = true
		}
	}
	return
}

func getAccessToken() (token interface{}, ok bool) {
	token = &AccessToken{}
	url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", AppId, AppKey)
	if err := httpGet(url, token); err != nil {
		util.GetLogger().Error("[handle-getAccessToken] - error:%s", err.Error())
	} else {
		ok = true
	}
	return
}

func httpGet(url string, val interface{}) (err error) {
	var body []byte
	var rs *http.Response
	rs, err = http.Get(url)
	if rs != nil && rs.Body != nil {
		defer rs.Body.Close()
	}
	if err == nil {
		if body, err = ioutil.ReadAll(rs.Body); err == nil {
			err = json.Unmarshal(body, val)
		}
	}
	return
}
